package com.demo.config

import com.mysql.jdbc.jdbc2.optional.MysqlXADataSource
import org.apache.ibatis.session.SqlSessionFactory
import org.mybatis.spring.SqlSessionFactoryBean
import org.mybatis.spring.SqlSessionTemplate
import org.mybatis.spring.annotation.MapperScan
import org.springframework.beans.factory.annotation.Qualifier
import org.springframework.boot.context.properties.ConfigurationProperties
import org.springframework.boot.jta.atomikos.AtomikosDataSourceBean
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.stereotype.Component
import javax.sql.DataSource

open class DBConfigContent {
    var url: String? = null
    var username: String? = null
    var password: String? = null
    var minPoolSize = 0
    var maxPoolSize = 0
    var maxLifetime = 0
    var borrowConnectionTimeout = 0
    var loginTimeout = 0
    var maintenanceInterval = 0
    var maxIdleTime = 0
    var testQuery: String? = null
}

@Component
@ConfigurationProperties(prefix = "spring.datasource.db1")
class DB1ConfigContent : DBConfigContent()

@Configuration
@MapperScan(basePackages = ["com.demo.db.mybatis.db1.mapper"], sqlSessionFactoryRef = "db1SqlSessionFactory")
class DB1Config {
    @Bean(name = ["db1DataSource"])
    fun db1DataSource(config: DB1ConfigContent): DataSource {
        val mysqlXaDataSource = MysqlXADataSource()
        mysqlXaDataSource.setUrl(config.url)
        mysqlXaDataSource.pinGlobalTxToPhysicalConnection = true
        mysqlXaDataSource.setPassword(config.password)
        mysqlXaDataSource.user = config.username
        mysqlXaDataSource.pinGlobalTxToPhysicalConnection = true
        val xaDataSource = AtomikosDataSourceBean()
        xaDataSource.xaDataSource = mysqlXaDataSource
        xaDataSource.uniqueResourceName = "db1DataSource"
        xaDataSource.minPoolSize = config.minPoolSize
        xaDataSource.maxPoolSize = config.maxPoolSize
        xaDataSource.maxLifetime = config.maxLifetime
        xaDataSource.borrowConnectionTimeout = config.borrowConnectionTimeout
        xaDataSource.loginTimeout = config.loginTimeout
        xaDataSource.maintenanceInterval = config.maintenanceInterval
        xaDataSource.maxIdleTime = config.maxIdleTime
        xaDataSource.testQuery = config.testQuery
        return xaDataSource
    }

    @Bean(name = ["db1SqlSessionFactory"])
    @Throws(Exception::class)
    fun db1SqlSessionFactory(@Qualifier("db1DataSource") dataSource: DataSource): SqlSessionFactory {
        val bean = SqlSessionFactoryBean()
        bean.setDataSource(dataSource)
        return bean.getObject()!!
    }

    @Bean(name = ["db1SqlSessionTemplate"])
    fun db1SqlSessionTemplate(@Qualifier("db1SqlSessionFactory") sqlSessionFactory: SqlSessionFactory): SqlSessionTemplate {
        val tmp = SqlSessionTemplate(sqlSessionFactory)
        tmp.configuration.isMapUnderscoreToCamelCase = true
        return tmp
    }
}

@Component
@ConfigurationProperties(prefix = "spring.datasource.db2")
class DB2ConfigContent : DBConfigContent()

@Configuration
@MapperScan(basePackages = ["com.demo.db.mybatis.db2.mapper"], sqlSessionFactoryRef = "db2SqlSessionFactory")
class DB2Config {
    @Bean(name = ["db2DataSource"])
    fun db2DataSource(config: DB2ConfigContent): DataSource {
        val mysqlXaDataSource = MysqlXADataSource()
        mysqlXaDataSource.setUrl(config.url)
        mysqlXaDataSource.pinGlobalTxToPhysicalConnection = true
        mysqlXaDataSource.setPassword(config.password)
        mysqlXaDataSource.user = config.username
        mysqlXaDataSource.pinGlobalTxToPhysicalConnection = true
        val xaDataSource = AtomikosDataSourceBean()
        xaDataSource.xaDataSource = mysqlXaDataSource
        xaDataSource.uniqueResourceName = "db2DataSource"
        xaDataSource.minPoolSize = config.minPoolSize
        xaDataSource.maxPoolSize = config.maxPoolSize
        xaDataSource.maxLifetime = config.maxLifetime
        xaDataSource.borrowConnectionTimeout = config.borrowConnectionTimeout
        xaDataSource.loginTimeout = config.loginTimeout
        xaDataSource.maintenanceInterval = config.maintenanceInterval
        xaDataSource.maxIdleTime = config.maxIdleTime
        xaDataSource.testQuery = config.testQuery
        return xaDataSource
    }

    @Bean(name = ["db2SqlSessionFactory"])
    @Throws(Exception::class)
    fun db2SqlSessionFactory(@Qualifier("db2DataSource") dataSource: DataSource): SqlSessionFactory {
        val bean = SqlSessionFactoryBean()
        bean.setDataSource(dataSource)
        return bean.getObject()!!
    }

    @Bean(name = ["db2SqlSessionTemplate"])
    fun db2SqlSessionTemplate(@Qualifier("db2SqlSessionFactory") sqlSessionFactory: SqlSessionFactory): SqlSessionTemplate {
        val tmp = SqlSessionTemplate(sqlSessionFactory)
        tmp.configuration.isMapUnderscoreToCamelCase = true
        return tmp
    }
}
